package BaseObject;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class Taxi {

	private static int pas = 1;
	private int occupiedPlaces;
	private Point2D.Double currentPositionTaxi;
	private Itinerary itinerary;
	private ArrayList<Client> takenClientList;//Clients who are in this taxi

	public static int comparator;
	public static int COMPARATOR_LENGTH = 0;
	public static int COMPARATOR_PROBA = 1;
	public static int COMPARATOR_MIX = 2;

	public Taxi(int occupiedPlaces,Point2D.Double currentPositionTaxi){
		this.occupiedPlaces = occupiedPlaces;
		this.itinerary = null;
		this.currentPositionTaxi=currentPositionTaxi;
		this.takenClientList = new ArrayList<Client>();

	}

	public Taxi(){
		choixPositionApparition();
		this.itinerary = null;
		this.takenClientList = new ArrayList<Client>();
	}


	public void calculItinerary(){
		System.out.println("Entering in Compute Itinerary");

		if(this.takenClientList.size()==2)
			return;

		if(Motor.clients.size()==0 && this.takenClientList.size()==0)
			this.setItinerary(null);

		if(this.takenClientList.size()!=2)
		{
			ArrayList<Itinerary> itineraries = this.bestPath();

			Iterator<Itinerary> it = itineraries.iterator();

			if(Taxi.comparator == Taxi.COMPARATOR_LENGTH)
				Collections.sort(itineraries,new ComparatorDistance());

			if(Taxi.comparator == Taxi.COMPARATOR_PROBA)
				Collections.sort(itineraries,new ComparatorProba());

			if(Taxi.comparator == Taxi.COMPARATOR_MIX)
				Collections.sort(itineraries,new ComparatorMix());

			it = itineraries.iterator();

			while(it.hasNext()){
				it.next();
			}

			if(itineraries.size()!= 0){
				this.itinerary = itineraries.get(0);
			}
			else if(this.takenClientList.size()==1){
				this.itinerary = new Itinerary4(this.takenClientList.get(0),null);
			}		
		}
		System.out.println("Exiting Compute Itinerary  " );
	}

	public ArrayList<Itinerary> bestPath() {
		System.out.println("entering in BestPath");
		if(this.takenClientList.size()==2)
			return null;

		//Compute all the possible itineraries
		ArrayList<Itinerary> itineraries = new ArrayList<Itinerary>();

		if(this.takenClientList.size()==1){
			Client c = this.takenClientList.get(0);
			for(Client c2 : Motor.clients)	{
				if(!c.equals(c2)){
					Itinerary its[] = new Itinerary[4];
					its[0] = new Itinerary1(c,c2);
					its[1] = new Itinerary2(c,c2);
					its[2] = new Itinerary3(c,c2);
					its[3] = new Itinerary4(c,c2);

					for(int i=0;i<4;i++){
						if(its[i].computeItinerary(0))	{
							itineraries.add(its[i]);
						}
					}
				}
			}
			return itineraries;
		}

		//Vector<Itinerary> itineraries = new Vector<Itinerary>();
		if(Motor.clients.size()==1)
		{
			Itinerary4 it = new Itinerary4(Motor.clients.get(0),null);
			itineraries.add(it);
			return itineraries;
		}

		for(Client c1 : Motor.clients){
			for(Client c2 : Motor.clients){
				if(!c1.equals(c2)){
					Itinerary its[] = new Itinerary[4];
					its[0] = new Itinerary1(c1,c2);
					its[1] = new Itinerary2(c1,c2);
					its[2] = new Itinerary3(c1,c2);
					its[3] = new Itinerary4(c1,c2);

					for(int i=0;i<4;i++){
						if(its[i].computeItinerary(this.currentPositionTaxi.distance(c1.getPosition()))){
							itineraries.add(its[i]);
						}
					}
				}
			}
		}

		return itineraries;
	}


	public boolean deplacerTaxi(Point2D.Double position){
		if(currentPositionTaxi.equals(position)){
			return true;
		}
		double z = currentPositionTaxi.distance(position);
		double fx = Math.abs(currentPositionTaxi.x - position.getX() );
		double fy = Math.abs(currentPositionTaxi.y - position.getY() );
		double fxx = pas/z*fx;
		double fyy = pas/z*fy;

		if(currentPositionTaxi.x <= position.getX() && currentPositionTaxi.y <= position.getY() )//1
		{
			currentPositionTaxi.x +=fxx;
			currentPositionTaxi.y +=fyy;

			this.updateClientPosition(currentPositionTaxi);

			if(currentPositionTaxi.x >= position.getX() && currentPositionTaxi.y >= position.getY())
			{
				this.currentPositionTaxi.x = position.getX();
				this.currentPositionTaxi.y = position.getY();
				return true;
			}

		}
		else if(currentPositionTaxi.x >= position.getX() && currentPositionTaxi.y <= position.getY())//2
		{
			currentPositionTaxi.x -=fxx;
			currentPositionTaxi.y +=fyy;

			this.updateClientPosition(currentPositionTaxi);

			if(currentPositionTaxi.x <= position.getX() && currentPositionTaxi.y >= position.getY())
			{
				this.currentPositionTaxi.x = position.getX();
				this.currentPositionTaxi.y = position.getY();
				return true;
			}
		}
		else if(currentPositionTaxi.x >= position.getX() && currentPositionTaxi.y >= position.getY() )//3
		{
			currentPositionTaxi.x -=fxx;
			currentPositionTaxi.y -=fyy;

			this.updateClientPosition(currentPositionTaxi);

			if(currentPositionTaxi.x <= position.getX() && currentPositionTaxi.y <= position.getY() )
			{
				this.currentPositionTaxi.x = position.getX();
				this.currentPositionTaxi.y = position.getY();
				return true;
			}
		}
		else if(currentPositionTaxi.x <= position.getX() && currentPositionTaxi.y >= position.getY() )//4
		{
			currentPositionTaxi.x +=fxx;
			currentPositionTaxi.y -=fyy;

			this.updateClientPosition(currentPositionTaxi);

			if(currentPositionTaxi.x >= position.getX() && currentPositionTaxi.y <= position.getY() )
			{
				this.currentPositionTaxi.x = position.getX();
				this.currentPositionTaxi.y = position.getY();
				return true;
			}
		}
		return false;
	}

	public void updateClientPosition(Point2D.Double position){
		for(int i=0;i<this.takenClientList.size();i++)
		{
			this.takenClientList.get(i).setPosition(position);
		}
	}

	public void move(){
		System.out.println("Entering in move");
		if(this.takenClientList.size()==0 && itinerary !=null){
			Client c = itinerary.clientItinerary.get(0);
			boolean change = this.deplacerTaxi(c.getPosition());

			if(change && Motor.clients.contains(c)){
				this.takenClientList.add(c);
				Motor.clients.remove(c);
				Motor.clientsTaken.add(c);
				Motor.increaseNbClientDone();
			}
		}
		else{

			if(itinerary instanceof Itinerary1)
			{
				((Itinerary1) itinerary).moveThisTaxi(this);
			}
			else if(itinerary instanceof Itinerary2)
			{
				((Itinerary2) itinerary).moveThisTaxi(this);
			}
			else if(itinerary instanceof Itinerary3)
			{
				((Itinerary3) itinerary).moveThisTaxi(this);
			}
			else if(itinerary instanceof Itinerary4)
			{
				((Itinerary4) itinerary).moveThisTaxi(this);
			}
		}

		System.out.println("Exiting move");

	}

	public Point2D.Double getCurrentPositionTaxi() {
		return currentPositionTaxi;
	}

	public void setCurrentPositionTaxi(Point2D.Double currentPositionTaxi) {
		this.currentPositionTaxi = currentPositionTaxi;
	}


	public int getOccupiedPlaces() {
		return occupiedPlaces;
	}

	public void setOccupiedPlaces(int occupiedPlaces) {
		// +1 quand un client arrive
		// Si occupiedPlace == 2, setstatus = 2
		this.occupiedPlaces = occupiedPlaces;
	}


	public Point2D.Double getPosition() {
		return currentPositionTaxi;
	}

	public void setPosition(Point2D.Double currentPositionTaxi) {
		this.currentPositionTaxi = currentPositionTaxi;
	}

	public Itinerary getItinerary() {
		return itinerary;
	}

	public void setItinerary(Itinerary itinerary) {
		//en fonction clients dans le taxi + client en attente sur son chemin qu'il pourrait prendre
		this.itinerary = itinerary;
	}

	public ArrayList<Client> getTekenClientList() {
		return takenClientList;
	}

	public void setTekenClientList(ArrayList<Client> tekenClientList) {
		this.takenClientList = tekenClientList;
	}

	public void choixPositionApparition(){
		int min = -Motor.cityRay;
		int max = Motor.cityRay;

		double x = min + (Math.random() * (max-min));
		double y = min + (Math.random() * (max-min)); 
		//methode de rejet
		while (! ((x*x + y*y) <= (Motor.cityRay*Motor.cityRay))){
			x = min + (Math.random() * (max-min));
			y = min + (Math.random() * (max-min)); 
		}
		this.currentPositionTaxi= new Point2D.Double(x,y);
	}
}
